package ED2;

import edu.uci.ics.jung.algorithms.layout.FRLayout2;
import edu.uci.ics.jung.algorithms.layout.Layout;
import edu.uci.ics.jung.algorithms.shortestpath.DijkstraShortestPath;
import edu.uci.ics.jung.visualization.BasicVisualizationServer;
import edu.uci.ics.jung.visualization.RenderContext;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
import edu.uci.ics.jung.visualization.control.ModalGraphMouse;
import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;
import edu.uci.ics.jung.visualization.renderers.Renderer;
import edu.uci.ics.jung.visualization.transform.shape.GraphicsDecorator;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Paint;
import java.awt.Shape;
import java.awt.geom.CubicCurve2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.collections15.Transformer;

public class ManipulaGrafo
{
    public static final Paint DEFAULT_SOURCE_COLOR = Color.GREEN;
    public static final Paint DEFAULT_TARGET_COLOR = Color.WHITE;
    public static final Paint DEFAULT_PATH_COLOR_LEVEL_1 = Color.YELLOW;
    public static final Paint DEFAULT_PATH_COLOR_LEVEL_2 = Color.MAGENTA;
    public static final Paint DEFAULT_PATH_COLOR_LEVEL_3 = Color.RED;
    public static final Paint DEFAULT_PATH_COLOR_LEVEL_4 = Color.PINK;
    public static final Paint DEFAULT_PATH_COLOR_LEVEL_5 = Color.ORANGE;
    public static final Paint[] DEFAULT_PATH_LEVEL_COLORS = {DEFAULT_PATH_COLOR_LEVEL_1, DEFAULT_PATH_COLOR_LEVEL_2, DEFAULT_PATH_COLOR_LEVEL_3, DEFAULT_PATH_COLOR_LEVEL_4, DEFAULT_PATH_COLOR_LEVEL_5};
    
    private View view;
    private Layout<Vertex, Edge> layout;
    private VisualizationViewer<Vertex, Edge> visualizationViewer;
    private ManipulaDados dataManager;
    
    public ManipulaGrafo(Dimension dimension)
    {
        dataManager = new ManipulaDados();
        
        view = new View();
        
        layout = new FRLayout2  <Vertex, Edge>(view);
        layout.setSize(dimension);
        
        DefaultModalGraphMouse defaultModalGraphMouse = new DefaultModalGraphMouse(1.0f, 1.0f);
        defaultModalGraphMouse.setMode(ModalGraphMouse.Mode.PICKING);
        
        visualizationViewer = new VisualizationViewer<Vertex, Edge>(layout);
        visualizationViewer.setGraphMouse(defaultModalGraphMouse);
        visualizationViewer.setSize(dimension);
        visualizationViewer.getRenderContext().setVertexLabelTransformer(new ToStringLabeller());
        visualizationViewer.getRenderer().getVertexLabelRenderer().setPosition(Renderer.VertexLabel.Position.CNTR);
        
        visualizationViewer.getRenderer().setVertexRenderer(new Renderer.Vertex<Vertex, Edge>()
        {
            @Override
            public void paintVertex(RenderContext<Vertex, Edge> rc, Layout<Vertex, Edge> layout, Vertex v)
            {
                GraphicsDecorator graphicsContext = rc.getGraphicsContext();
                Point2D center = layout.transform(v);
                
               
                 Shape shape = new Ellipse2D.Double(center.getX() - 25, center.getY() - 8, 50, 15);
                
                 
                graphicsContext.setPaint(v.getColor());
                graphicsContext.fill(shape);
            }
        });
        
        visualizationViewer.getRenderContext().setEdgeDrawPaintTransformer(new Transformer<Edge, Paint>()
        {
            @Override
            public Paint transform(Edge edge)
            {
                return edge.getColor();
            }
        });
    }
    
    public View getView()
    {
        return view;
    }
    
    public Layout<Vertex, Edge> getLayout()
    {
        return layout;
    }
    
    public BasicVisualizationServer<Vertex, Edge> getVisualizationViewer()
    {
        return visualizationViewer;
    }
    
    public void removeFilter()
    {
        for(Edge edge : view.getEdges())
        {
            edge.setColor(Edge.DEFAULT_COLOR);
            
            visualizationViewer.getRenderContext().getEdgeDrawPaintTransformer().transform(edge);
        }
        
        for(Vertex vertex : view.getVertices())
        {
            vertex.setColor(Vertex.DEFAULT_COLOR);
            
            visualizationViewer.getRenderContext().getVertexDrawPaintTransformer().transform(vertex);
        }
        
        visualizationViewer.repaint();
    }
    
    public List<Edge> calculateShortestPath(int sourceRm, int targetRm)
    {
        removeFilter();
        
        DijkstraShortestPath dijkstra = new DijkstraShortestPath(view);
        List<Edge> shortestPath = dijkstra.getPath(view.getVertexes().get(sourceRm), view.getVertexes().get(targetRm));
        
        for(Edge edge : shortestPath)
        {
            edge.setColor(DEFAULT_SOURCE_COLOR);
            
            visualizationViewer.getRenderContext().getEdgeDrawPaintTransformer().transform(edge);
        }
        
        Vertex sourceVertex = view.getVertexes().get(sourceRm);
        sourceVertex.setColor(DEFAULT_SOURCE_COLOR);
        
        Vertex targetVertex = view.getVertexes().get(targetRm);
        targetVertex.setColor(DEFAULT_TARGET_COLOR);
        
        visualizationViewer.getRenderContext().getVertexDrawPaintTransformer().transform(sourceVertex);
        visualizationViewer.getRenderContext().getVertexDrawPaintTransformer().transform(targetVertex);
        
        visualizationViewer.repaint();
        
        return shortestPath;
    }
    
    public List<Vertex> calculateUntouchableVertexes(int sourceRm)
    {
        removeFilter();
        
        ArrayList<Vertex> untouchableVertexes = new ArrayList<Vertex>();
        
        for(AlunoBean aluno : dataManager.getUntouchableAlunos(sourceRm))
        {
            untouchableVertexes.add(view.getVertexes().get(aluno.getRm()));
        }
        
        Vertex sourceVertex = view.getVertexes().get(sourceRm);
        sourceVertex.setColor(DEFAULT_SOURCE_COLOR);        
        
        visualizationViewer.getRenderContext().getVertexDrawPaintTransformer().transform(sourceVertex);
        
        for(Vertex vertex : untouchableVertexes)
        {
            vertex.setColor(DEFAULT_TARGET_COLOR);
            
            visualizationViewer.getRenderContext().getVertexDrawPaintTransformer().transform(vertex);
        }
        
        visualizationViewer.repaint();
        
        return untouchableVertexes;
    }
    
    public List<List<Vertex>> calculateTouchableVertexes(int sourceRm)
    {
        return calculateTouchableVertexes(sourceRm, -1);
    }
    
    public List<List<Vertex>> calculateTouchableVertexes(int sourceRm, int maxDeep)
    {
        removeFilter();
        
        ArrayList<List<Vertex>> touchableVertexes = new ArrayList<List<Vertex>>();
        ArrayList<Edge> path = new ArrayList<Edge>();
        
        for(ArrayList<AlunoBean> alunos : dataManager.getTouchableAlunos(sourceRm, maxDeep))
        {
            ArrayList<Vertex> tmpVertexes = new ArrayList<Vertex>();
            
            for(AlunoBean aluno : alunos)
            {
                tmpVertexes.add(view.getVertexes().get(aluno.getRm()));
            }

            touchableVertexes.add(tmpVertexes);
        }
        
        Vertex sourceVertex = view.getVertexes().get(sourceRm);
        sourceVertex.setColor(DEFAULT_SOURCE_COLOR);
        
        for(int i = 0, iLen = touchableVertexes.size(); i < iLen; i++)
        {
            for(int j = 0, jLen = touchableVertexes.get(i).size(); j < jLen; j++)
            {
                if(i == 0)
                {
                    Edge edge = getEdgeBetweenVertexes(sourceVertex, touchableVertexes.get(i).get(j));
                    edge.setColor(DEFAULT_PATH_LEVEL_COLORS[i]);
                    
                    path.add(edge);
                }
                else
                {
                    for(int k = 0, kLen = touchableVertexes.get(i - 1).size(); k < kLen; k++)
                    {
                        Edge edge = getEdgeBetweenVertexes(touchableVertexes.get(i - 1).get(k), touchableVertexes.get(i).get(j));
                        
                        if(edge != null)
                        {
                            edge.setColor(DEFAULT_PATH_LEVEL_COLORS[i]);
                            
                            path.add(edge);
                        }
                    }
                }
            }
        }
        
        visualizationViewer.getRenderContext().getVertexDrawPaintTransformer().transform(sourceVertex);
        
        for(List<Vertex> vertexes : touchableVertexes)
        {
            for(Vertex vertex : vertexes)
            {
                vertex.setColor(DEFAULT_TARGET_COLOR);

                visualizationViewer.getRenderContext().getVertexDrawPaintTransformer().transform(vertex);
            }
        }
        
        for(Edge edge: path)
        {
            visualizationViewer.getRenderContext().getEdgeDrawPaintTransformer().transform(edge);
        }
        
        visualizationViewer.repaint();
        
        return touchableVertexes;
    }
    
    public Edge getEdgeBetweenVertexes(Vertex sourceVertex, Vertex targetVertex)
    {
        return view.getGraphEdges().get(view.generateEdgeKey(sourceVertex.getRm(), targetVertex.getRm()));
    }
}
